from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import base64
from PIL import Image
from io import BytesIO
from time import sleep
import requests

"""
传入出现滑块验证码的浏览器对象
自动处理完验证码
无返回
"""


class CaptchaSolver:
	def __init__(self, driver):
		self.driver = driver
		self.error_num = 0
		self.ex_yzm()
	def is_slider_captcha(self):
		try:
			element = WebDriverWait(self.driver, 10).until(
				EC.presence_of_element_located((By.CSS_SELECTOR, "p.passMod_slide-tip.slideShine"))
			)
			if element.text == "请向右滑动完成拼图":
				print("检测到滑块类验证码")
				return True
			else:
				# print("未检测到滑块类验证码文本")
				return False
		except Exception as e:
			# print("未检测到滑块类验证码元素")
			return False

	def get_captcha_image(self):
		captcha_img = WebDriverWait(self.driver, 10).until(
			EC.presence_of_element_located((By.CSS_SELECTOR, ".passMod_puzzle-background"))
		)
		# print("找到验证码背景图片")
		sleep(3)

		self.driver.execute_script("""
            var elements = document.querySelectorAll('.passMod_puzzle-block');
            elements.forEach(function(element) {
                element.style.display = 'none';
            });
        """)

		location = captcha_img.location
		size = captcha_img.size
		# print(f"位置是：{location}，尺寸是：{size}")

		png = self.driver.get_screenshot_as_png()

		# # 调试
		# with open('screenshot.png', 'wb') as f:  # 以二进制写入模式打开文件
		# 	f.write(png)

		image = Image.open(BytesIO(png))
		# 获取浏览器尺寸
		width = self.driver.execute_script("return window.innerWidth")
		height = self.driver.execute_script("return window.innerHeight")
		# print(f"浏览器宽度：{width}, 高度：{height}")
		# 重新设置截图尺寸，避免部分显示器导致的截图翻倍的问题
		fixed_image = image.resize((width,height))
		left = location['x']
		top = location['y']
		right = left + size['width']
		bottom = top + size['height']

		# print(f"图片的坐标为左：{left} 右：{right} 上：{top} 下：{bottom}")
		captcha_image = fixed_image.crop((left, top, right, bottom))
		# print("验证码截图已截取")
		# captcha_image.save('captcha.png')

		self.driver.execute_script("""
			var elements = document.querySelectorAll('.passMod_puzzle-block');
				elements.forEach(function(element) {
					element.style.display = '';
			});
		""")

		# buffered = BytesIO()
		# captcha_image.save(buffered, format="PNG")
		# img_base64 = base64.b64encode(buffered.getvalue()).decode('utf-8')
		# print("验证码图片已转换为base64格式")
		#
		# return img_base64
		# 保存图像为PNG格式，并转换为base64格式返回
		try:
			buffered = BytesIO()
			captcha_image.save(buffered, format="PNG")
			img_base64 = base64.b64encode(buffered.getvalue()).decode('utf-8')
			# print("验证码图片已转换为base64格式")
			return img_base64
		except Exception as e:
			print(f"验证码图片保存错误: {e}")
			return None
	def solve_captcha(self, x_offset):
		slider = WebDriverWait(self.driver, 10).until(
			EC.presence_of_element_located((By.CSS_SELECTOR, ".passMod_slide-btn"))
		)
		# print("找到滑块元素")

		action = ActionChains(self.driver)
		action.click_and_hold(slider).perform()
		# print("按住滑块")

		target_offset = x_offset - 23
		# print(f"目标偏移量: {target_offset}")

		total_movement = 0
		while total_movement < target_offset:
			step = min(10, target_offset - total_movement)
			action.move_by_offset(step, 0).perform()
			total_movement += step
			sleep(0.005)
		# print(f"将滑块移动到最终偏移量: {total_movement}")
		sleep(0.5)
		action.release().perform()
		# print("释放滑块")

	def get_cjy_zb(self, img="", file_type="file_base64"):

		url = "http://upload.chaojiying.net/Upload/Processing.php"
		user = "jindl0605"
		softid = "7064dd5019ec5e32fa834f129ba8bc67"
		password = "--Oscar0605"
		codetype = "9101"
		len_min = 0
		max_retries = 5

		data = {
			"user": user,
			"pass": password,
			"softid": softid,
			"codetype": codetype,
			"len_min": len_min,
			file_type: img
		}

		for attempt in range(max_retries):
			response = requests.post(url, data=data)
			# print(f"请求状态码: {response.status_code}")
			if response.status_code == 200:
				result = response.json()
				if result["err_no"] == 0:
					return result["pic_str"]
				else:
					print(f"错误信息: {result['err_str']}")
					return None
			else:
				print(f"请求失败，重试 {attempt + 1}/{max_retries} 次")
				sleep(10)

		print("多次请求失败，结束处理")
		return None

	def ex_yzm(self):
		while True:
			if self.is_slider_captcha():
				img = self.get_captcha_image()
				# print('开始识别')
				coords = self.get_cjy_zb(img)
				print(coords)
				self.error_num += 1
				if self.error_num == 10:
					print("连续10次出错,请检查")
					return False
				if coords is None:
					print("本次处理出错，重新开始...")
					self.driver.refresh()
					continue

				# print(f"解析得到的坐标: {coords}")
				try:
					first_coords = coords.split('|')[0]
					x, y = map(int, first_coords.split(','))
					# print(x)
				except Exception as e:
					print(f"解析坐标时出错: {e}")
					self.driver.refresh()
					continue

				self.solve_captcha(x)
				sleep(3)

				try:
					WebDriverWait(self.driver, 10).until_not(
						EC.url_contains("seccaptcha.baidu.com")
					)
					print("成功完成验证码验证")
					break
				except Exception as e:
					print(f"验证失败，继续尝试: {e}")
					continue
			else:
				print("不是滑块类验证码，刷新页面...")
				self.driver.refresh()

		print("滑块验证码处理完成")
		self.driver.refresh()
		sleep(10)
		return True
